#pragma once
#include <iostream>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

#include "InetAddr.hpp"
#include "LogMessage.hpp"
#include "Socket.hpp"
#include "Protocol.hpp"

using callback_t = std::function<bool(std::string &, std::string *)>;

class TcpServer;

struct ThreadData
{
public:
    ThreadData(TcpSocket *&serverSock, TcpServer *self)
        : _serverSock(serverSock), _self(self)
    {
    }

public:
    TcpSocket *_serverSock;
    TcpServer *_self;
};

class TcpServer
{
public:
    TcpServer(uint16_t port, callback_t cb)
        : headler_request(cb)
    {
        _listenSock = new TcpSocket();
        _listenSock->CreateBindListenSocket(port);
    }

    ~TcpServer()
    {
        _listenSock->CloseSockfd();
        delete _listenSock;
    }

    void Start()
    {
        while (true)
        {
            InetAddr addr;
            TcpSocket *serverSock = (TcpSocket *)_listenSock->AcceptConnect(addr);
            lg.LogMessage(Normal, "%s connect success, serverSock: %d", addr.GetUser().c_str(), serverSock->GetSockfd());

            pthread_t p;
            ThreadData *data = new ThreadData(serverSock, this);
            pthread_create(&p, nullptr, Routine, data);
        }
    }

    static void *Routine(void *arg)
    {
        pthread_detach(pthread_self());
        ThreadData *data = static_cast<ThreadData *>(arg);

        std::string buffer;
        InetAddr addr;
        while (true)
        {
            ssize_t n = data->_serverSock->Recvfrom(buffer, &addr);
            if (n > 0)
            {
                // 对请求进行构建相应
                std::string out;
                data->_self->headler_request(buffer, &out);

                // 将数据发送回去
                data->_serverSock->Sendto(out, addr);
            }
            else if (n == 0)
            {
                lg.LogMessage(Normal, "you close connect, me too");
                break;
            }
            else
            {
                lg.LogMessage(Warning, "recvfrom error");
                break;
            }
        }

        data->_serverSock->CloseSockfd();
        delete data->_serverSock;
        delete data;
    }

private:
    TcpSocket *_listenSock;

public:
    callback_t headler_request;
};
